package watcher

import (
	"fmt"
	"os/user"
	"strings"
	"time"

	"../pb"
)

type SingleProcess struct {
	pid       int
	ctime     int64
	checkTime int64
	user      user.User
}

func (sp *SingleProcess) Uptime() int64 {
	return time.Now().Unix() - sp.ctime
}
func (sp *SingleProcess) Info(b bool) string {
	t := time.Now().Unix()
	if sp.pid == 0 {
		if !b {
			return fmt.Sprintf("\tstatus: exited")
		}
		return fmt.Sprintf("\tstatus: exited, check: %d (seconds) ago",
			t-sp.checkTime)
	}
	if !b {
		return fmt.Sprintf("\tstatus: running")
	}
	return fmt.Sprintf("\tstatus: running, created: %d (seconds) ago , check: %d (seconds) ago",
		t-sp.ctime, t-sp.checkTime)
}
func (sp *SingleProcess) Status(port string) (*pb.Status, error) {
	if sp.pid == 0 {
		return nil, nil
	}
	stat, err := GetStatus(sp.pid, port)
	checkErr(err)
	sp.checkTime = time.Now().Unix()
	stat.ProcType = "Single"
	return stat, err
}

func (sp *SingleProcess) Add(uname user.User, ctime int64, pid int) (err error) {
	if sp.pid == 0 {
		sp.pid = pid
		sp.user = uname
		sp.ctime = ctime
		sp.checkTime = time.Now().Unix()
		return
	}
	return fmt.Errorf("Duplicate Process Matched In Single define")
}

type MultiProcess struct {
	processes []*SingleProcess
}

func (sp *MultiProcess) Uptime() int64 {
	var sum int64
	var count int
	for _, v := range sp.processes {
		count += 1
		sum += time.Now().Unix() - v.ctime
	}
	return sum / int64(count)
}

func (sp *MultiProcess) Add(uname user.User, ctime int64, pid int) error {
	p := &SingleProcess{}
	if err := p.Add(uname, ctime, pid); err != nil {
		return err
	}
	sp.processes = append(sp.processes, p)
	return nil
}
func (sp *MultiProcess) Info(b bool) string {
	var s []string
	if len(sp.processes) == 0 {
		return fmt.Sprintf("\tstatus: none,")
	}
	for i, p := range sp.processes {
		s = append(s, fmt.Sprintf("\t%d%s", i, p.Info(b)))
	}
	return strings.Join(s, "\n")
}
func (sp *MultiProcess) Status(port string) (*pb.Status, error) {
	stat := &pb.Status{}
	for _, p := range sp.processes {
		s, err := p.Status(port)
		if err != nil {
			return nil, err
		}
		if !IsNull(s) {
			Addto(stat, s)
		}
	}
	stat.ProcType = "Multi"
	return stat, nil
}
